package com.mspbots.core.ticketai.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.databind.JsonNode;
import com.mspbots.core.AbstractBaseServiceImpl;
import com.mspbots.core.ticketai.mapper.BoardMapper;
import com.mspbots.core.ticketai.mapper.TicketMapper;
import com.mspbots.core.ticketai.model.Board;
import com.mspbots.core.ticketai.model.BoardAssociationsVo;
import com.mspbots.core.ticketai.model.BoardOnly;
import com.mspbots.core.ticketai.model.Ticket;
import com.mspbots.core.ticketai.service.BoardAssociationsService;
import com.mspbots.core.ticketai.service.BoardService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * com.mspbots.core.ticketai.service.impl.BoardServiceImpl
 *
 * @author Alex bob(https://github.com/vnobo)
 * @date Created by 2019/12/11
 */
@Service
public class BoardServiceImpl extends AbstractBaseServiceImpl<BoardMapper, Board>
        implements BoardService {

    private final BoardAssociationsService boardAssociationsService;

    @Autowired
    private TicketMapper ticketMapper;

    public BoardServiceImpl(BoardAssociationsService boardAssociationsService) {
        this.boardAssociationsService = boardAssociationsService;
    }

    @Override
    public List<BoardOnly> getListOnly(Long tenantId, Long cwUid) {
        List<Board> boards = super.list(Wrappers.<Board>lambdaQuery().eq(Board::getTenantId, tenantId)
                .eq(Board::getInactiveFlag, false)
                .select(Board::getId, Board::getCwId, Board::getName, Board::getExtend, Board::getTenantId)
                .orderByAsc(Board::getId));
        List<BoardAssociationsVo> boardAssociations = boardAssociationsService.getBoardAssociations(tenantId);
        List<BoardOnly> boardOnlys = new ArrayList<>();

        boards.forEach(board -> {
            boolean flag = true;
            if (!StringUtils.isEmpty(cwUid) && !ObjectUtils.isEmpty(board.getExtend().get("excludedMembers"))) {
                Iterator<JsonNode> elements = board.getExtend().get("excludedMembers").elements();
                while (elements.hasNext()) {
                    JsonNode node = elements.next();
                    if (cwUid.equals(node.get("memberId").asLong())) {
                        flag = false;
                        break;
                    }
                }
            }
            if (flag) {
                BoardOnly only = new BoardOnly();
                BeanUtils.copyProperties(board, only);
                only.setStatuses(board.getExtend().get("status"));
                only.setExcludedMembers(board.getExtend().get("excludedMembers"));

                List<Long> types = board.getExtend().get("types") == null ? new ArrayList<>() : board.getExtend().get("types")
                        .findValuesAsText("id").stream().map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
                List<Long> subtypes = board.getExtend().get("subtypes") == null ? new ArrayList<>() : board.getExtend().get("subtypes")
                        .findValuesAsText("id").stream().map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
                List<Long> items = board.getExtend().get("items") == null ? new ArrayList<>() : board.getExtend().get("items")
                        .findValuesAsText("id").stream().map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());

                Optional.ofNullable(boardAssociations).ifPresent(bo ->
                        bo.stream().filter(a -> board.getCwId().equals(a.getBoardId()) && !CollectionUtils.isEmpty(a.getTypes()))
                                .findAny().ifPresent(b -> {
                            b.setTypes(b.getTypes().stream().filter(u -> types.contains(u.getId())).collect(Collectors.toList()));
                            Optional.ofNullable(b.getTypes()).ifPresent(t ->
                                    t.forEach(s -> {
                                        s.setSubTypes(s.getSubTypes().stream().filter(u -> subtypes.contains(u.getId())).collect(Collectors.toList()));
                                        Optional.ofNullable(s.getSubTypes()).ifPresent(i -> i.forEach(e -> {
                                            e.setItems(e.getItems().stream().filter(u -> items.contains(u.getId())).collect(Collectors.toList()));
                                        }));
                                    }));
                            only.setTypes(b.getTypes());
                        })
                );
                boardOnlys.add(only);
            }
        });
        boardOnlys.sort(Comparator.comparing(BoardOnly::getName));
        return boardOnlys;
    }

    @Override
    public Board getBoardByTimeEntry(Long tenantId, Long chargeToId) {
        Ticket ticket = this.ticketMapper.selectOne(Wrappers.<Ticket>lambdaQuery().eq(Ticket::getCwId, chargeToId)
                .eq(Ticket::getTenantId, tenantId));
        if (!ObjectUtils.isEmpty(ticket)) {
            Board board = this.baseMapper.selectOne(Wrappers.<Board>lambdaQuery().eq(Board::getCwId, ticket.getBoardId())
                    .eq(Board::getTenantId, tenantId));
            if (!ObjectUtils.isEmpty(board)) {
                return board;
            } else {
                return null;
            }
        } else {
            return null;
        }

    }
}
